home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / ip.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  11KB  |  444 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #define    TLB        30    /* Reassembly limit time */
  6. #include <stdio.h>
  7. #include "machdep.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "internet.h"
  11. #include "ip.h"
  12. #include "icmp.h"
  13. #include "iface.h"
  14.  
  15. int ip_recv();    /* Should be void, but C complains */
  16. char *calloc(),*malloc();
  17.  
  18. char ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  19.  
  20. struct reasm *reasmq;
  21.  
  22. #define    INSERT    0
  23. #define    APPEND    1
  24. #define    PREPEND    2
  25.  
  26. /* Send an IP datagram. Modeled after the example interface on p 32 of
  27.  * RFC 791
  28.  */
  29. void
  30. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  31. int32 source;        /* source address */
  32. int32 dest;        /* Destination address */
  33. char protocol;        /* Protocol */
  34. char tos;        /* Type of service */
  35. char ttl;        /* Time-to-live */
  36. struct mbuf *bp;    /* Data portion of datagram */
  37. int16 length;        /* Optional length of data portion */
  38. int16 id;        /* Optional identification */
  39. char df;        /* Don't-fragment flag */
  40. {
  41.     struct mbuf *hbp;    /* mbuf containing IP header */
  42.     struct ip_header *iph;    /* Pointer to IP header */
  43.     static int16 id_cntr;    /* Datagram serial number */
  44.     int16 hdr_len;        /* IP header length, bytes */
  45.     void ip_route();    /* Datagram router */
  46.  
  47.     if(length == 0 && bp != NULLBUF)
  48.         length = len_mbuf(bp);
  49.     if(id == 0)
  50.         id = id_cntr++;        
  51.     if(ttl == 0)
  52.         ttl = ip_ttl;
  53.  
  54.     /* Allocate an mbuf for the IP header */
  55.     hdr_len = sizeof(struct ip_header);
  56.     if((hbp = alloc_mbuf(hdr_len)) == NULLBUF){
  57.         /* We really ought to source-quench the sender, but that would
  58.          * probably fail too.
  59.          */
  60.         free_p(bp);
  61.         return;
  62.     }
  63.     hbp->cnt = hdr_len;
  64.  
  65.     /* and fill it in */
  66.     iph = (struct ip_header *)hbp->data;
  67.  
  68.     iph->v_ihl = (IPVERSION << 4) | (hdr_len/sizeof(int32));
  69.     iph->tos = tos;
  70.     iph->length = htons(hdr_len + length);
  71.     iph->id = htons(id);
  72.     if(df)
  73.         iph->fl_offs = htons(DF);
  74.     else
  75.         iph->fl_offs = 0;
  76.     iph->ttl = ttl;
  77.     iph->protocol = protocol;
  78.     iph->checksum = 0;
  79.     iph->source = htonl(source);
  80.     iph->dest = htonl(dest);
  81.     iph->checksum = cksum(NULLHEADER,hbp,hdr_len);
  82.     hbp->next = bp;
  83.     ip_route(hbp,0);        /* Toss it to the router */
  84. }
  85.  
  86. /* Reassemble incoming IP fragments and dispatch completed datagrams
  87.  * to the proper transport module
  88.  */
  89. int    /* Should really be void */
  90. ip_recv(bp,rxbroadcast)
  91. struct mbuf *bp;
  92. char rxbroadcast;
  93. {
  94.     register struct ip_header *ipp;    /* Pointer to original IP header */
  95.     struct ip_header ip;    /* Extracted copy of header */
  96.     int16 ip_len;        /* Length of IP header */
  97.     struct mbuf *fraghandle();
  98.     void (*recv)();    /* Function to call with completed datagram */
  99.     void tcp_input(),udp_input(),icmp_input();
  100.  
  101.     ipp = (struct ip_header *)bp->data;
  102.  
  103.     /* Initial check for protocols we can't handle */
  104.     switch(ipp->protocol & 0xff){
  105.     case TCP_PTCL:
  106.         recv = tcp_input;
  107.         break;
  108.     case UDP_PTCL:
  109.         recv = udp_input;
  110.         break;
  111.     case ICMP_PTCL:
  112.         recv = icmp_input;
  113.         break;
  114.     default:
  115.         /* Send an ICMP Protocol Unknown response... */
  116.         ip_stats.badproto++;
  117.         /* ...unless it's a broadcast */
  118.         if(!rxbroadcast)
  119.             icmp_output(bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  120.         free_p(bp);
  121.         return;
  122.     }
  123.     ip_len = lonibble(ipp->v_ihl) * sizeof(int32);
  124.     /* Extract IP header */
  125.     pullup(&bp,(char *)&ip,ip_len);
  126.  
  127.     /* Convert to host byte order */
  128.     ip.length = ntohs(ip.length) - ip_len;    /* Length of data portion */
  129.     ip.id = ntohs(ip.id);
  130.     ip.fl_offs = ntohs(ip.fl_offs);
  131.     ip.source = ntohl(ip.source);
  132.     ip.dest = ntohl(ip.dest);
  133.  
  134.     /* If we have a complete packet, call the next layer
  135.      * to handle the result
  136.      */
  137.     if((bp = fraghandle(&ip,bp)) != NULLBUF)
  138.         (*recv)(bp,ip.protocol,ip.source,ip.dest,ip.tos,ip.length,rxbroadcast);
  139. }
  140. /* Process IP datagram fragments
  141.  * If datagram is complete, return it with ip->length containing its
  142.  * entire length; otherwise return NULLBUF
  143.  */
  144. static
  145. struct mbuf *
  146. fraghandle(ip,bp)
  147. struct ip_header *ip;    /* IP header, host byte order */
  148. struct mbuf *bp;    /* The fragment itself */
  149. {
  150.     void ip_timeout(),freefrag(),free_reasm();
  151.     struct reasm *lookup_reasm(),*creat_reasm();
  152.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  153.     struct frag *lastfrag,*nextfrag,*tfp,*newfrag();
  154.     struct mbuf *tbp;
  155.     int16 i;
  156.     int16 offset;        /* Index of first byte in fragment */
  157.     int16 last;        /* Index of first byte beyond fragment */
  158.     char mf;        /* 1 if not last fragment, 0 otherwise */
  159.  
  160.     offset = (ip->fl_offs & F_OFFSET) << 3;    /* Convert to bytes */
  161.     last = offset + ip->length;
  162.     mf = (ip->fl_offs & MF) ? 1 : 0;
  163.  
  164.     rp = lookup_reasm(ip);
  165.     if(offset == 0 && !mf){
  166.         /* Complete datagram received. Discard any earlier fragments */
  167.         if(rp != NULLREASM)
  168.             free_reasm(rp);
  169.  
  170.         return bp;
  171.     }
  172.     if(rp == NULLREASM){
  173.         /* First fragment; create new reassembly descriptor */
  174.         if((rp = creat_reasm(ip)) == NULLREASM){
  175.             /* No space for descriptor, drop fragment */
  176.             free_p(bp);
  177.             return NULLBUF;
  178.         }
  179.     }
  180.     /* Keep restarting timer as long as we keep getting fragments */
  181.     stop_timer(&rp->timer);
  182.     start_timer(&rp->timer);
  183.  
  184.     /* If this is the last fragment, we now know how long the
  185.      * entire datagram is; record it
  186.      */
  187.     if(!mf)
  188.         rp->length = last;
  189.  
  190.     /* Set nextfrag to the first fragment which begins after us,
  191.      * and lastfrag to the last fragment which begins before us
  192.      */
  193.     lastfrag = NULLFRAG;
  194.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  195.         if(nextfrag->offset > offset)
  196.             break;
  197.         lastfrag = nextfrag;
  198.     }
  199.     /* Check for overlap with preceeding fragment */
  200.     if(lastfrag != NULLFRAG  && offset < lastfrag->last){
  201.         /* Strip overlap from new fragment */
  202.         i = lastfrag->last - offset;
  203.         pullup(&bp,NULLCHAR,i);
  204.         if(bp == NULLBUF)
  205.             return NULLBUF;    /* Nothing left */
  206.         offset += i;
  207.     }
  208.     /* Look for overlap with succeeding segments */
  209.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  210.         tfp = nextfrag->next;    /* save in case we delete fp */
  211.  
  212.         if(nextfrag->offset >= last)
  213.             break;    /* Past our end */
  214.         /* Trim the front of this entry; if nothing is
  215.          * left, remove it.
  216.          */
  217.         i = last - nextfrag->offset;
  218.         pullup(&nextfrag->buf,NULLCHAR,i);
  219.         if(nextfrag->buf == NULLBUF){
  220.             /* superseded; delete from list */
  221.             if(nextfrag->prev != NULLFRAG)
  222.                 nextfrag->prev->next = nextfrag->next;
  223.             else
  224.                 rp->fraglist = nextfrag->next;
  225.             if(tfp->next != NULLFRAG)
  226.                 nextfrag->next->prev = nextfrag->prev;
  227.             freefrag(nextfrag);
  228.         } else
  229.             nextfrag->offset = last;
  230.     }
  231.     /* Lastfrag now points, as before, to the fragment before us;
  232.      * nextfrag points at the next fragment. Check to see if we can
  233.      * join to either or both fragments.
  234.      */
  235.     i = INSERT;
  236.     if(lastfrag != NULLFRAG && lastfrag->last == offset)
  237.         i |= APPEND;
  238.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  239.         i |= PREPEND;
  240.     switch(i){
  241.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  242.         tfp = newfrag(offset,last,bp);
  243.         tfp->prev = lastfrag;
  244.         tfp->next = nextfrag;
  245.         if(lastfrag != NULLFRAG)
  246.             lastfrag->next = tfp;    /* Middle of list */
  247.         else
  248.             rp->fraglist = tfp;    /* First on list */
  249.         if(nextfrag != NULLFRAG)
  250.             nextfrag->prev = tfp;
  251.         break;
  252.     case APPEND:    /* Append to lastfrag */
  253.         append(&lastfrag->buf,bp);
  254.         lastfrag->last = last;    /* Extend forward */
  255.         break;
  256.     case PREPEND:    /* Prepend to nextfrag */
  257.         tbp = nextfrag->buf;
  258.         nextfrag->buf = bp;
  259.         append(&nextfrag->buf,tbp);
  260.         nextfrag->offset = offset;    /* Extend backward */
  261.         break;
  262.     case (APPEND|PREPEND):
  263.         /* Consolidate by appending this fragment and nextfrag
  264.          * to lastfrag and removing the nextfrag descriptor
  265.          */
  266.         append(&lastfrag->buf,bp);
  267.         append(&lastfrag->buf,nextfrag->buf);
  268.         nextfrag->buf = NULLBUF;
  269.         lastfrag->last = nextfrag->last;
  270.  
  271.         /* Finally unlink and delete the now unneeded nextfrag */
  272.         lastfrag->next = nextfrag->next;
  273.         if(nextfrag->next != NULLFRAG)
  274.             nextfrag->next->prev = lastfrag;
  275.         freefrag(nextfrag);
  276.         break;
  277.     }
  278.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  279.         && rp->length != 0){
  280.         /* We've gotten a complete datagram, so extract it from the
  281.          * reassembly buffer and pass it on.
  282.          */
  283.         bp = rp->fraglist->buf;
  284.         rp->fraglist->buf = NULLBUF;
  285.         ip->length = rp->length;    /* Tell IP the entire length */
  286.         free_reasm(rp);
  287.         return bp;
  288.     } else
  289.         return NULLBUF;
  290. }
  291. static struct reasm *
  292. lookup_reasm(ip)
  293. struct ip_header *ip;
  294. {
  295.     register struct reasm *rp;
  296.  
  297.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  298.         if(ip->source == rp->source && ip->dest == rp->dest
  299.          && ip->protocol == rp->protocol && ip->id == rp->id)
  300.             return rp;
  301.     }
  302.     return NULLREASM;
  303. }
  304. #ifdef    FOO
  305. static
  306. int16
  307. hash_reasm(source,dest,protocol,id)
  308. int32 source;
  309. int32 dest,
  310. char protocol;
  311. int16 id;
  312. {
  313.     register int16 hval;
  314.  
  315.     hval = loword(source);
  316.     hval ^= hiword(source);
  317.     hval ^= loword(dest);
  318.     hval ^= hiword(dest);
  319.     hval ^= protocol & 0xff;
  320.     hval ^= id;
  321.     hval %= RHASH;
  322.     return hval;
  323. }
  324. #endif
  325. /* Create a reassembly descriptor,
  326.  * put at head of reassembly list
  327.  */
  328. static struct reasm *
  329. creat_reasm(ip)
  330. register struct ip_header *ip;
  331. {
  332.     register struct reasm *rp;
  333.  
  334.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  335.         return rp;    /* No space for descriptor */
  336.     rp->source = ip->source;
  337.     rp->dest = ip->dest;
  338.     rp->id = ip->id;
  339.     rp->protocol = ip->protocol;
  340.     rp->timer.start = TLB;
  341.     rp->timer.func = ip_timeout;
  342.     rp->timer.arg = (int *)rp;
  343.  
  344.     rp->next = reasmq;
  345.     if(rp->next != NULLREASM)
  346.         rp->next->prev = rp;
  347.     reasmq = rp;
  348.     return rp;
  349. }
  350.  
  351. /* Free all resources associated with a reassembly descriptor */
  352. static void
  353. free_reasm(rp)
  354. register struct reasm *rp;
  355. {
  356.     register struct frag *fp;
  357.  
  358.     stop_timer(&rp->timer);
  359.     /* Remove from list of reassembly descriptors */
  360.     if(rp->prev != NULLREASM)
  361.         rp->prev->next = rp->next;
  362.     else
  363.         reasmq = rp->next;
  364.     if(rp->next != NULLREASM)
  365.         rp->next->prev = rp->prev;
  366.     /* Free any fragments on list, starting at beginning */
  367.     while((fp = rp->fraglist) != NULLFRAG){
  368.         rp->fraglist = fp->next;
  369.         free_p(fp->buf);
  370.         free((char *)fp);
  371.     }
  372.     free((char *)rp);
  373. }
  374.  
  375. /* Handle reassembly timeouts by deleting all reassembly resources */
  376. static void
  377. ip_timeout(arg)
  378. int *arg;
  379. {
  380.     register struct reasm *rp;
  381.  
  382.     rp = (struct reasm *)arg;
  383.     free_reasm(rp);
  384. }
  385. /* Create a fragment */
  386. static
  387. struct frag *
  388. newfrag(offset,last,bp)
  389. int16 offset,last;
  390. struct mbuf *bp;
  391. {
  392.     struct frag *fp;
  393.  
  394.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  395.         /* Drop fragment */
  396.         free_p(bp);
  397.         return NULLFRAG;
  398.     }
  399.     fp->buf = bp;
  400.     fp->offset = offset;
  401.     fp->last = last;
  402.     return fp;
  403. }
  404. /* Delete a fragment, return next one on queue */
  405. static
  406. void
  407. freefrag(fp)
  408. struct frag *fp;
  409. {
  410.     free_p(fp->buf);
  411.     free((char *)fp);
  412. }
  413. #ifdef TRACE
  414. int
  415. doipstat(argc,argv)
  416. int argc;
  417. char *argv[];
  418. {
  419.     extern struct ip_stats ip_stats;
  420.     extern struct reasm *reasmq;
  421.     register struct reasm *rp;
  422.     register struct frag *fp;
  423.     char *inet_ntoa();
  424.  
  425.     printf("total %ld runt %u len err %u vers err %u",
  426.         ip_stats.total,ip_stats.runt,ip_stats.length,ip_stats.version);
  427.     printf(" chksum err %u badproto %u\r\n",
  428.         ip_stats.checksum,ip_stats.badproto);
  429.  
  430.     if(reasmq != NULLREASM)
  431.         printf("Reassembly fragments:\r\n");
  432.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  433.         printf("src %s",inet_ntoa(rp->source));
  434.         printf(" dest %s",inet_ntoa(rp->dest));
  435.         printf(" id %u pctl %u time %u len %u\r\n",
  436.             rp->id,rp->protocol,rp->timer.count,rp->length);
  437.         for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  438.             printf(" offset %u last %u\r\n",fp->offset,fp->last);
  439.         }
  440.     }
  441.     return 0;
  442. }
  443. #endif
  444.